package com.edu.app.controller.login;

import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.edu.app.bean.core.SysFile;
import com.edu.app.bean.core.SysRole;
import com.edu.app.bean.core.SysTenant;
import com.edu.app.bean.core.SysUser;

import com.edu.app.bean.linkbeans.SysUserWxUserBind;
import com.edu.app.constant.ErrorConstant;
import com.edu.app.constant.StaticConstant;
import com.edu.app.constant.SysMessage;
import com.edu.app.exception.BaseException;
import com.edu.app.exception.WechatBindException;
import com.edu.app.mapper.core.SysFileMapper;
import com.edu.app.model.UserModel;
import com.edu.app.service.sys.core.SysRoleService;
import com.edu.app.service.sys.core.SysTenantService;
import com.edu.app.service.sys.core.SysUserService;
import com.edu.app.service.sys.linkservices.SysUserRoleService;
import com.edu.app.service.sys.linkservices.SysUserWxUserService;
import com.edu.app.service.sys.security.SysSecurityService;
import com.edu.app.threadlocal.TenantContext;
import com.edu.app.util.ErrorUtil;
import com.edu.app.util.JWTUtil;
import com.edu.app.util.MsgUtil;
import com.edu.app.util.SecurityUtil;

import com.edu.app.util.alisms.AliyunMessageUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;

import java.util.Date;
import java.util.List;
import java.util.Map;

@RequestMapping("/api/auth")
@RestController
public class SysLoginController {

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private SysUserRoleService sysUserRoleService;

    @Autowired
    private SysSecurityService sysSecurityService;

    @Autowired
    private SysTenantService sysTenantService;

    @Autowired
    private SysRoleService sysRoleService;

    @Autowired
    private SysUserWxUserService sysUserWxUserService;

    @Autowired
    private SysFileMapper sysFileMapper;

    Logger logger = LoggerFactory.getLogger(SysLoginController.class);
    /*
     * 用户注册分两步：
     * 1 验证码校验
     * 2 用户添加
     * 测试链接： http://localhost:8080/api/auth/signup?code=486076&hashcode=fde2e5e44a2cd79f0e4826cc0ffa4e28
     * */
    @PostMapping("/signup")
    @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,timeout=36000,rollbackFor=Exception.class)
    public ModelMap signup (@RequestBody SysUser user,
                            @RequestParam(value="openId",required = false) String openid,
                            @RequestParam String code,
                            @RequestParam String hashcode,
                            @RequestParam String company){

        //校验验证码的合法性
        if(!sysSecurityService.validateVerifyCode(code, hashcode, user.getUsername())){
            return ErrorUtil.retErrMsg(ErrorConstant.INVALID_VERIFICATION);
        }

        //继续添加合法用户
        try{
            sysUserService.createTenantUser(user,company);
            if(StringUtils.isNotEmpty(openid)){
                SysUserWxUserBind sysUserWxUserBind =
                        sysUserWxUserService.createUserWxUserBind(
                                user,
                                user.getTenant_id(),
                                openid
                        );

            }
            sysUserService.assignRole2TenantUser(user);
            return MsgUtil.retMsg(SysMessage.SIGNUP_SUCCEED, null,null);
        }
        catch(WechatBindException wbe){
            logger.error(wbe.getStackTrace().toString());
            throw new BaseException(ErrorConstant.INVALID_WXUSER,wbe.getMessage());
            //return ErrorUtil.retErrMsg(ErrorConstant.INVALID_WXUSER);
        }
        catch (org.springframework.dao.DuplicateKeyException dupe){
            logger.error(dupe.getStackTrace().toString());
            //TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new BaseException(ErrorConstant.USER_ALREADY_EXISTS,dupe.getMessage());
            //return ErrorUtil.retErrMsg(ErrorConstant.USER_ALREADY_EXISTS);
        }
        catch (Exception e){
            //TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            //return ErrorUtil.retErrMsg(e);
            logger.error(e.getStackTrace().toString());
            throw new BaseException(ErrorConstant.SERVER_INTERNAL_ERROR,e.getMessage());
        }

    }


//    @PostMapping(value = "/wechatlogin")
//    @Transactional(rollbackFor=Exception.class)
//    public ModelMap  wechatlogin(@RequestParam("openId") String openid) {
//
//        try {
//
//            SysWxUser sysWxUser =sysUserWxUserService.getWxUser(openid);
//            if(sysWxUser == null){
//                return ErrorUtil.retErrMsg(ErrorConstant.USER_NOT_ACTIVE);
//            }
//
//
//        }  finally {
//            //TenantContext.setNeedTenantId(Boolean.TRUE);
//        }
//        ModelMap m = MsgUtil.retMsg(SysMessage.LOGIN_SUCCEED,
//                                    StaticConstant.TOKEN,
//                                    JWTUtil.sign(username, encodePassword));
//        return m;
//    }


    @PostMapping(value = "/login")
    @Transactional(rollbackFor=Exception.class)
    public ModelMap login(@RequestParam("username") String username,
                          @RequestParam("password") String password,
                          @RequestParam(value = "openId", required = false) String openid) {

        try {
            TenantContext.setNeedTenantId(Boolean.FALSE);
            SysUser sysUser = sysUserService.getUserByName(username);

            if (sysUser == null) {
                return ErrorUtil.retErrMsg(ErrorConstant.USER_NOT_EXISTS);
            }

            if (sysUser.getStatus() == 0) {
                return ErrorUtil.retErrMsg(ErrorConstant.USER_NOT_ACTIVE);
            }

            String encodePassword = SecurityUtil.getEncryptCode(password, username);
            if (sysUser.getPassword().equals(encodePassword)) {
                SysTenant sysTenant = sysTenantService.getObjectById(sysUser.getTenant_id());
                if (StringUtils.isNotEmpty(openid)) {
                    SysUserWxUserBind sysUserWxUserBind = sysUserWxUserService.createUserWxUserBind(
                            sysUser,
                            sysTenant.getId(),
                            openid);

                }
                //更新登陆时间
                sysUser.setLast_login_time(new Date());
                sysUserService.update(sysUser);
                List<SysRole> sysRoleList = sysUserRoleService.getRoleListByUserId(sysUser.getId());
                SysFile sysFile = sysFileMapper.selectById(sysUser.getHead_img_id());
                UserModel userModel = new UserModel(sysUser, sysRoleList, sysTenant, sysFile);
                ModelMap m = MsgUtil.retMsg(SysMessage.LOGIN_SUCCEED, StaticConstant.TOKEN, JWTUtil.sign(username, encodePassword));

                //添加User信息返回
                m.put(StaticConstant.USER_MODEL, userModel);

                return m;
            } else {
                return ErrorUtil.retErrMsg(ErrorConstant.INVALID_USER_OR_PASSWORD);
            }
        } catch (WechatBindException wbe) {
            logger.error(wbe.getStackTrace().toString());
            throw new BaseException(ErrorConstant.INVALID_WXUSER,wbe.getMessage());
        } finally {
            TenantContext.setNeedTenantId(Boolean.TRUE);
        }
    }


    @RequestMapping("/401")
    public ModelMap unauthorizedRole(){
        return ErrorUtil.retErrMsg(ErrorConstant.UNAUTHORIZED_ROLE);
    }

    @GetMapping("/verifycode")
    public ModelMap getVerifyCode(@RequestParam String phoneNumber){

        Map<String, String> paramMap = sysSecurityService.getVerifyCodeParam(phoneNumber.replace(" ",""));

        try{
            SendSmsResponse sendSmsResponse = AliyunMessageUtil.sendSms(paramMap);
            if(!(sendSmsResponse.getCode() != null && sendSmsResponse.getCode().equals("OK"))) {
                if(sendSmsResponse.getCode() == null) {
                    //这里可以抛出自定义异常
                }
                if(!sendSmsResponse.getCode().equals("OK")) {
                    //这里可以抛出自定义异常
                }
            }
        }catch(Exception e){
            return ErrorUtil.retErrMsg(ErrorConstant.SERVER_INTERNAL_ERROR_MESSAGE);
        }

        String code = paramMap.get("code");
        return MsgUtil.retMsg(SysMessage.GET_VERIFY_CODE_SUCCEED,
                StaticConstant.HASHCODE,
                sysSecurityService.getHashCode(code, phoneNumber)
        );
    }

    /*
    * 校验验证码
    * http://localhost:8080/api/auth/validateVerifyCode?code=865635&hashcode=fb181be6766ba0ef36b6d8d07c27b589
    * */
    @GetMapping("/validateVerifyCode")
    public ModelMap validateVerifyCode(@RequestParam String code, @RequestParam String hashcode, @RequestParam String userPattern){

        if(sysSecurityService.validateVerifyCode(code, hashcode, userPattern)){
            return MsgUtil.retMsg(SysMessage.VALID_VERIFY_CODE, null, null);
        }else {
            return ErrorUtil.retErrMsg(ErrorConstant.INVALID_VERIFICATION);
        }
    }

    @GetMapping("/checkToken")
    @RequiresAuthentication
    public ModelMap checkToken(){
        return MsgUtil.retMsg(SysMessage.VERIFY_TOKEN_SUCCEED, null, null);
    }

    @PostMapping("/bindWxOpenId")
    @RequiresAuthentication
    public ModelMap bindWxOpenId(@RequestHeader("Authorization") String token, @RequestParam String openId){
        try{
            String username = JWTUtil.getUsername(token);
            SysUser sysUser = sysUserService.getUserByName(username);
            sysUser.initializeUpdateSystemColumns(username);
            sysUser.setWx_open_id(openId);
            sysUserService.update(sysUser);
            return MsgUtil.retMsg(SysMessage.BIND_OPENID_SUCCEED, null, null);
        }catch (Exception e){
            return ErrorUtil.retErrMsg(ErrorConstant.SERVER_INTERNAL_ERROR);
        }
    }

    @PostMapping("/unbindWxOpenId")
    @RequiresAuthentication
    public ModelMap bindWxOpenId(@RequestHeader("Authorization") String token){
        try{
            String username = JWTUtil.getUsername(token);
            SysUser sysUser = sysUserService.getUserByName(username);
            sysUser.initializeUpdateSystemColumns(username);
            sysUser.setWx_open_id(null);
            sysUserService.update(sysUser);
            return MsgUtil.retMsg(SysMessage.BIND_OPENID_SUCCEED, null, null);
        }catch (Exception e){
            return ErrorUtil.retErrMsg(ErrorConstant.SERVER_INTERNAL_ERROR);
        }
    }

}
